package com.wlz.creational.singleton;


import com.wlz.creational.singleton.enumSingleton.Singleton;
import com.wlz.creational.singleton.hunger.HungrySingleton;
import com.wlz.creational.singleton.lazy.LazySingleton;
import org.junit.Test;

import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * @author： wlz
 * @Date 2020/7/21 10:15
 * @description： TODO
 * @version: 1.0
 *  利用反射破坏单例模式
 */
public class reflectionMain {

    /**
     *饿汉式   通过反射攻击
     * 解决思路：在构造函数中抛异常
     *         private HungerSingleton01() {
     *           if(instance!=null){
     *              throw  new  RuntimeException("禁止通过反射创建对象");
     *           }
     *         }
     */
    @Test
    public void test1() throws Exception {

        // 获取类的显式构造器
        Constructor constructor = HungrySingleton.class.getDeclaredConstructor();

        // 可访问私有构造器
        constructor.setAccessible(true);

        // 利用反射构造新对象
        Object newInstance = constructor.newInstance();
        System.out.println(newInstance.hashCode());

        // 通过正常方式获取单例对象
        System.out.println(HungrySingleton.getInstance().hashCode());
    }

    /**
     * 懒汉式 反射攻击
     *  结论：如果是先执行反射，无法防止了
     * @throws Exception
     */
    @Test
    public void test2() throws Exception {
        Class clazz = LazySingleton.class;
        Constructor constructor = clazz.getDeclaredConstructor();

        constructor.setAccessible(true);
        Object newInstance = constructor.newInstance();

        LazySingleton instance = LazySingleton.getInstance();

        System.out.println(instance.hashCode());
        System.out.println(newInstance.hashCode());
    }

    /**
     * 枚举防止反射攻击
     * @throws Exception
     */
    @Test
    public void test3() throws Exception {
        Class clazz = Singleton.class;
        Constructor constructor = clazz.getDeclaredConstructor(String.class,int.class);
        constructor.setAccessible(true);
        constructor.newInstance("ant",10);

    }


}
